//
//  DataHandler.m
//  GroupDeal
//
//  Created by lewang on 14-5-21.
//  Copyright (c) 2014年 groupdeal. All rights reserved.
//

#import "DataHandler.h"
#import <CoreData/CoreData.h>
#import "AFNetworking.h"
#import "BaseUrlConfig.h"

#define DATE_ATTR_PREFIX @"dAtEaTtr:"

@implementation DataHandler


#pragma mark - from NSDictionary to NSManagedObject
+ (void)SetValuesForKeysWithDictionary:(NSDictionary *)keyedValues dateFormatter:(NSDateFormatter *)dateFormatter  ToObject:(NSManagedObject *)object
{
    NSDictionary *attributes = [[object entity] attributesByName];
    
    
    for (NSString *attribute in attributes)
    {
      
        
        id value = [keyedValues objectForKey:attribute];
        if (value == nil || value == [NSNull null])
        {
            // Don't attempt to set nil, or you'll overwite values in self that aren't present in keyedValues
            continue;
        }
        
        NSAttributeType attributeType = [[attributes objectForKey:attribute] attributeType];
        if ((attributeType == NSStringAttributeType) && ([value isKindOfClass:[NSNumber class]])) {
            value = [value stringValue];
        }
        else if ((attributeType == NSBooleanAttributeType) && ([value isKindOfClass:[NSString class]]))
        {
            NSString *strTmp = (NSString *)value;
            if ([strTmp isEqualToString:@"Y"]) {
                value = [NSNumber numberWithBool:YES];
            }else{
                value = [NSNumber numberWithBool:NO];
            }
        }
        
        else if (((attributeType == NSInteger16AttributeType) || (attributeType == NSInteger32AttributeType) || (attributeType == NSInteger64AttributeType) ) && ([value isKindOfClass:[NSString class]]))
        {
            value = [NSNumber numberWithInteger:[value integerValue]];
        }
        else if ((attributeType == NSFloatAttributeType) &&  ([value isKindOfClass:[NSString class]]))
        {
            value = [NSNumber numberWithDouble:[value doubleValue]];
        }
        else if ((attributeType == NSDateAttributeType) && ([value isKindOfClass:[NSString class]]) && (dateFormatter != nil))
        {
            value = [dateFormatter dateFromString:value];
        }
        [object setValue:value forKey:attribute];
    }
}

+ (void)SetValuesForKeysWithDictionary:(NSDictionary *)keyedValues ToObject:(NSManagedObject *)object
{
    NSDictionary *attributes = [[object entity] attributesByName];
    for (NSString *attribute in attributes)
    {
        
        id value = [keyedValues objectForKey:attribute];
        
        if (value == nil || value == [NSNull null])
        {
            // Don't attempt to set nil, or you'll overwite values in self that aren't present in keyedValues
            continue;
        }
        
        NSAttributeType attributeType = [[attributes objectForKey:attribute] attributeType];
        
        
        if ((attributeType == NSStringAttributeType) && ([value isKindOfClass:[NSNumber class]]))
        {
            value = [value stringValue];
        }
        else if ((attributeType == NSBooleanAttributeType) && ([value isKindOfClass:[NSString class]]))
        {
            NSString *strTmp = (NSString *)value;
            if ([strTmp isEqualToString:@"Y"]) {
                value = [NSNumber numberWithBool:YES];
            }else{
                value = [NSNumber numberWithBool:NO];
            }
        }
        else if (((attributeType == NSInteger16AttributeType) || (attributeType == NSInteger32AttributeType) || (attributeType == NSInteger64AttributeType)) && ([value isKindOfClass:[NSString class]])) {
            value = [NSNumber numberWithInteger:[value integerValue]];
        }
        else if (((attributeType == NSFloatAttributeType) || (attributeType == NSDoubleAttributeType))
                 &&  ([value isKindOfClass:[NSString class]])) {
            value = [NSNumber numberWithDouble:[value doubleValue]];
        }
        else if (attributeType == NSBinaryDataAttributeType) {
            if ([value isKindOfClass:[NSString class]]) {
                NSData *dataValue = [value dataUsingEncoding:[NSString defaultCStringEncoding]];
                [object setValue:dataValue forKey:attribute];
                continue;
            }
            else if ([value isKindOfClass:[NSDictionary class]])
            {
                NSData *dataValue = [NSKeyedArchiver archivedDataWithRootObject:value];
                [object setValue:dataValue forKey:attribute];
                continue;
            }
        }
        else if ((attributeType == NSDateAttributeType) && ([value isKindOfClass:[NSString class]]))
        {
#warning set data from int
            //            value = [dateFormatter dateFromString:value];
        }
        [object setValue:value forKey:attribute];
    }
}
#pragma mark - from NSManagedObject to NSDictionary
+ (NSDictionary*)toDictionaryWithTraversalHistory:(NSMutableSet*)traversalHistory FromObject:(NSManagedObject *)object
{
    NSArray* attributes = [[[object entity] attributesByName] allKeys];
    NSArray* relationships = [[[object entity] relationshipsByName] allKeys];
    NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithCapacity:
                                 [attributes count] + [relationships count] + 1];
    
    NSMutableSet *localTraversalHistory = nil;
    
    if (traversalHistory == nil)
    {
        localTraversalHistory = [NSMutableSet setWithCapacity:[attributes count] + [relationships count] + 1];
    }
    else
    {
        localTraversalHistory = traversalHistory;
    }
    
    [localTraversalHistory addObject:object];
    [dict setObject:[[object class] description] forKey:@"class"];
    
    for (NSString* attr in attributes) {
        NSObject* value = [object valueForKey:attr];
        
        if (value != nil) {
            if ([value isKindOfClass:[NSDate class]])
            {
                NSTimeInterval date = [(NSDate*)value timeIntervalSinceReferenceDate];
                NSString *dateAttr = [NSString stringWithFormat:@"%@%@", DATE_ATTR_PREFIX, attr];
                [dict setObject:[NSNumber numberWithDouble:date] forKey:dateAttr];
            } else {
                [dict setObject:value forKey:attr];
            }
        }
    }
    
    for (NSString* relationship in relationships) {
        NSObject* value = [object valueForKey:relationship];
        
        
        // To-many relationship
        if ([value isKindOfClass:[NSSet class]])
        {
            // The core data set holds a collection of managed objects
            NSSet* relatedObjects = (NSSet*) value;
            
            // Our set holds a collection of dictionaries
            NSMutableArray* dictSet = [NSMutableArray arrayWithCapacity:[relatedObjects count]];
            
            //对所有relationship 进行递归
            for (NSManagedObject* relatedObject in relatedObjects)
            {
                if ([localTraversalHistory containsObject:relatedObject] == NO)
                {
                    [dictSet addObject:[DataHandler toDictionaryWithTraversalHistory:localTraversalHistory FromObject:relatedObject]];
                }
            }
            [dict setObject:[NSArray arrayWithArray:dictSet] forKey:relationship];
        }
        else if ([value isKindOfClass:[NSOrderedSet class]])
        {
            // To-many relationship
            // The core data set holds an ordered collection of managed objects
            NSOrderedSet* relatedObjects = (NSOrderedSet*) value;
            
            // Our ordered set holds a collection of dictionaries
            NSMutableArray* dictSet = [NSMutableArray arrayWithCapacity:[relatedObjects count]];
            for (NSManagedObject* relatedObject in relatedObjects) {
                if ([localTraversalHistory containsObject:relatedObject] == NO)
                {
                    [dictSet addObject:[DataHandler toDictionaryWithTraversalHistory:localTraversalHistory FromObject:relatedObject]];
                }
            }
            
            [dict setObject:[NSOrderedSet orderedSetWithArray:dictSet] forKey:relationship];
        }
        else if ([value isKindOfClass:[NSManagedObject class]])
        {
            // To-one relationship
            NSManagedObject* relatedObject = (NSManagedObject*) value;
            if ([localTraversalHistory containsObject:relatedObject] == NO)
            {
                // Call toDictionary on the referenced object and put the result back into our dictionary.
                
                [dict setObject:[DataHandler toDictionaryWithTraversalHistory:localTraversalHistory FromObject:relatedObject] forKey:relationship];
            }
        }
    }
    
    if (traversalHistory == nil) {
        [localTraversalHistory removeAllObjects];
    }
    
    return dict;
}

+ (NSDictionary*) toDictionaryFrom:(NSManagedObject *)object
{
    
    NSMutableSet *traversedObjects = nil;
    
    
    // Check to see there are any objects that should be skipped in the traversal.
    // This method can be optionally implemented by NSManagedObject subclasses.
    //    if ([self respondsToSelector:@selector(serializationObjectsToSkip)]) {
    //        traversedObjects = [self performSelector:@selector(serializationObjectsToSkip)];
    //    }
    
    
    return [DataHandler toDictionaryWithTraversalHistory:traversedObjects FromObject:object];
}


#pragma mark  - copy object to object
//====== 复制到数据库
+ (NSManagedObject*)copyObject:(NSManagedObject *)object
                     toContext:(NSManagedObjectContext*)moc
{
    NSManagedObject *newObject = [DataHandler copyObject:object toContext:moc parent:nil];
    return newObject;
}

+ (NSManagedObject*)copyObject:(NSManagedObject *)object
                     toContext:(NSManagedObjectContext*)moc
                        parent:(NSString*)parentEntity
{
    
    NSMutableDictionary *lookup = [[NSMutableDictionary alloc] init];
    
    NSString *entityName = [[object entity] name];
    
    //用于返回的object
    NSManagedObject *newObject = [NSEntityDescription
                                  insertNewObjectForEntityForName:entityName
                                  inManagedObjectContext:moc];
    
    [lookup setObject:newObject forKey:[object objectID]];//中转存储数据
    NSArray *attKeys = [[[object entity] attributesByName] allKeys];
    NSDictionary *attributes = [object dictionaryWithValuesForKeys:attKeys];
    
    [newObject setValuesForKeysWithDictionary:attributes];
    
    id oldDestObject = nil;
    id temp = nil;
    
    NSDictionary *relationships = [[object entity] relationshipsByName];
    for (NSString *key in [relationships allKeys])
    {
        NSRelationshipDescription *desc = [relationships valueForKey:key];
        NSString *destEntityName = [[desc destinationEntity] name];
        
        if ([destEntityName isEqualToString:parentEntity])//目标对象已经包含则不复制
            continue;
        
        if ([desc isToMany])
        {
            NSMutableSet *newDestSet = [NSMutableSet set];
            
            for (oldDestObject in [object valueForKey:key])
            {
                temp = [lookup objectForKey:[oldDestObject objectID]];
                if (!temp) {
                    temp = [self copyObject:oldDestObject
                                  toContext:moc
                                     parent:entityName];
                }
                [newDestSet addObject:temp];
            }
            
            [newObject setValue:newDestSet forKey:key];
        }
        else
        {
            oldDestObject = [object valueForKey:key];
            if (!oldDestObject) continue;
            
            temp = [lookup objectForKey:[oldDestObject objectID]];
            if (!temp && ![destEntityName isEqualToString:parentEntity])
            {
                temp = [self copyObject:oldDestObject
                              toContext:moc
                                 parent:entityName];
            }
            [newObject setValue:temp forKey:key];
        }
    }
    return newObject;
}







@end
